package com;

import java.util.HashSet;
import java.util.Set;

/**
 * 哈希表 : 又叫散列表,用来保存键值对 (key,value),就是一个数组中,每个元素都是一个单向链表
 * 根据添加元素的 hash 值,通过 hash 算法,就能够确定要把元素添加到哪个链表中
 * 
 * hash算法 : 一种安全的加密算法,把不定长的值,更改为定长的值,不能保证其值的唯一性
 * 
 * 其中算法包括 : 
 * 1.直接寻址法
 * 2.数字分析法
 * 3.平方取中法
 * 4.随机数法
 * 5.除留余数法
 * 
 * java 中屏蔽了散列数据结构,封装到了 HashMap/HashSet/Hash Table 中,其中HashTable已经过时
 * 
 * hash算法 : java中指的是 hashCode()函数
 * 目标 : 给每个对象生成一个唯一的标识符
 * 散列表的数组下标还是 0~ N,只不过根据 key 得到的hash 的值,在通过hash 短发,就能得到这个元素所在的下标
 * 
 * hash 的目的: 为了快速查询,hash值是一个固定的值,整型值,所在定长的情况下,查询极快
 * 
 * HashSet 和 HashMap:
 * 		1.HashSet就是HashMap的一个封装,只不过把 value 值屏蔽了
 * 		2.HashMap 中是 key.value 键值对,但是在HashSet中,只有 key
 * 
 * 如何向 hash 表中添加数据
 * 		1.添加的时候,HashMap 保存的是映射关系,这个映射关系靠Map.Entry(K,V)来维护,是一个接口
 * 			单向链表 : 每个节点有三部分
 * 					1.有一个Entry(K,V)
 * 					2.next
 * 					3.Hash值
 * 		2.添加过程:先调用要存储的映射关系的key对象,调用key对象的HashCode()方法,生成hash 码值
 * 		然后根据hash值通过hash算法 进行hash,得到数组下标,然后向数组中添加元素
 * 		如果数组中还没有对应的hash的数据就占用一个数组空间,保存这个 key-value 的映射关系
 * 		如果有,就调用 key 的equals 方法,挨个在 hash 值相同的链表中,进行比较,如果返回 true ,那么代表该链表中有这个 key
 * 		如果已有这个元素,key不添加,value值覆盖原来的value
 * 		如果equals方法返回 false 说明两个对象只是hash值相同,但并不是同一个对象
 * 		那么就把该对象插入到链表中
 * 
 * 		HashSet只保存一个对象
 * hashMap 保存键值对
 * 
 * 添加的元素,要实现 equals 方法和HashCode 方法
 * @author lenovo
 * @Date 2020年7月18日
 * @Time 上午9:36:05
 */
public class Collection_13_Set_01 {

	public static void main(String[] args) {
		Set s = new HashSet();
		s.add(1);
		s.add(1);
		s.add(2);// id=1
		System.out.println(s);

		HashSet hs = new HashSet();
		Employee e1 = new Employee("1000", "obama");
		Employee e2 = new Employee("1000", "obalv");
		Employee e3 = new Employee("2000", "张三");
		Employee e4 = new Employee("3000", "张三");
		Employee e5 = new Employee("4000", "张三");
		Employee e6 = new Employee("5000", "李四");

//		System.out.println(e1.hashCode());
//		System.out.println(e2.hashCode());
//		System.out.println(e3.hashCode());
//		System.out.println(e4.hashCode());
//		System.out.println(e5.hashCode());
//		System.out.println(e6.hashCode());
//		hashCode执行了
//		1507423
//		hashCode执行了
//		1507423
//		hashCode执行了
//		1537214
//		hashCode执行了
//		1567005
//		hashCode执行了
//		1596796
//		hashCode执行了
//		1626587

		hs.add(e1);
		// 如果重复就不添加
		hs.add(e2);
		hs.add(e3);
		hs.add(e4);
		hs.add(e5);
		hs.add(e6);
		for (Object object : hs) {
			System.out.println(object);
		}
//		hashCode执行了
//		hashCode执行了
//		equals执行了
//		hashCode执行了
//		hashCode执行了
//		hashCode执行了
//		hashCode执行了
//		Employee [no=5000, name=李四]
//		Employee [no=4000, name=张三]
//		Employee [no=1000, name=obama]
//		Employee [no=2000, name=张三]
//		Employee [no=3000, name=张三]

	}

}

class Employee {
	String no;
	String name;

	public Employee(String no, String name) {
		super();
		this.no = no;
		this.name = name;
	}

	@Override
	public boolean equals(Object obj) {
		System.out.println("equals执行了");
		if (this == obj) {
			return true;
		}
		if (obj instanceof Employee) {
			Employee e = (Employee) obj;
			if (no.equals(e.no)) {
				return true;
			}
		}
		return false;
	}

	static int i = 16;

	@Override
	public int hashCode() {
		System.out.println("hashCode执行了");
		return no.hashCode();
	}

	@Override
	public String toString() {
		return "Employee [no=" + no + ", name=" + name + "]";
	}
}